package com.xxx.confirm;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 * Rabbit Confirm发送方确认模式
 *  Confirm发送方确认模式使用和事务类似，也是通过设置Channel进行发送方确认的。
	Confirm的三种实现方式：
		方式一：channel.waitForConfirms()普通发送方确认模式；
		方式二：channel.waitForConfirmsOrDie()批量确认模式；
		方式三：channel.addConfirmListener()异步监听发送方确认模式；
		
	Confirm批量确定和Confirm异步模式性能相差不大，Confirm模式要比事务快10倍左右。
 * 
 * @author guweiqiang
 * 2018年6月13日
 */
public class Confirm3 {
	
	// 队列名称
	private static final String QUEUE_NAME = "rabbitMQ.confirm3";
	
	// rabbit MQ server host
	private static final String HOST = "localhost";

	public static void main(String[] args) throws IOException, TimeoutException {
		// 1.创建连接工厂，并设置工厂相关属性
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost(HOST); // MQ server
		
		// 2.创建一个连接
		Connection connection = factory.newConnection();
		
		// 3.创建一个通道
		Channel channel = connection.createChannel();
		
		// 4.声明一个队列
		channel.queueDeclare(QUEUE_NAME, false, false, false, null);
		// 第一个参数表示队列名称
		// 第二个参数为队列是否持久化（true表示是，队列将在服务器重启时生存）
		// 第三个参数为是否是独占队列（创建者可以使用的私有队列，断开后自动删除）
		// 第四个参数为当所有消费者客户端连接断开时是否自动删除队列
		// 第五个参数为队列的其他参数
		
		channel.confirmSelect(); // 开启发送方confirm模式
		// 5.批量发送消息
		for(int i=21; i<=30; i++) {
			String message = i+": hello world！ now is："+new Date().getTime();
			System.out.println("confirm3 send message：" + message);
			channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
		}

		// 方式三：channel.addConfirmListener()异步监听发送方确认模式；
		// 异步模式的优点，就是执行效率高，不需要等待消息执行完，只需要监听消息即可
		channel.addConfirmListener(new ConfirmListener() {

			// multiple的参数，此参数为bool值，如果true表示批量执行了deliveryTag这个值以前的所有消息，如果为false的话表示单条确认。
			@Override
			public void handleAck(long deliveryTag, boolean multiple) throws IOException {
				System.out.println("未确认消息，标识：" + deliveryTag);
			}

			// multiple的参数，此参数为bool值，如果true表示批量执行了deliveryTag这个值以前的所有消息，如果为false的话表示单条确认。
			@Override
			public void handleNack(long deliveryTag, boolean multiple) throws IOException {
				System.out.println(String.format("已确认消息，标识：%d，多个消息：%b", deliveryTag, multiple));
			}
		});
		
		// 6.关闭连接
		channel.close();
		connection.close();
		
		System.out.println("执行完成："+new Date().getTime());
	}

}
